package DecisionTree;

import java.util.ArrayList;

import DataModel.*;

public class DecisionTree {

	/**
	 * Indexes in the array list (not feature ids!!!!!!)
	 */
	public ArrayList<Integer> usedFeatures;
	
	public DecisionTree(){
		this.usedFeatures = new ArrayList<>();
	}
	
	/**
	 * Final set of movies returned after traversing tree
	 */
	public ArrayList<Movie> finalMovies;
	
	public ArrayList<Evaluation> finalEvals;
	/**
	 * @param root
	 */
	

	
	public Node buildTree(Node root){

		root.entropy=Entropy.CalcEntropy(root.evaluations);
		if(root.entropy==0) return root;  //if entropy is zero we are finished
		int bestFeatureId = -1;
		double bestInfoGain = 0;
		
		for (int featureId = 0; featureId < root.evaluatedMovies.get(0).features.size(); featureId++) {
			boolean used=false;
			for(Integer checked : usedFeatures){
				if(checked==featureId) {
					used=true;		//ignore feature if it was already used
				}
				}
			
			if(used==false){
			ArrayList<Movie> trueMovieEvals=getDividedMovies(root.evaluatedMovies, featureId, true);
			ArrayList<Movie> falseMovieEvals=getDividedMovies(root.evaluatedMovies, featureId, false);
			double entropyTrue = Entropy.CalcEntropy(getEvaluationsForMovies(trueMovieEvals, root.evaluations));
			double entropyFalse = Entropy.CalcEntropy(getEvaluationsForMovies(falseMovieEvals, root.evaluations));
			double entropyTotal= ((double)trueMovieEvals.size()/(double)root.evaluations.size())*entropyTrue+
								((double)falseMovieEvals.size()/(double)root.evaluations.size())*entropyFalse;
			double information_gain=root.entropy-entropyTotal;
			
			if(information_gain > bestInfoGain) {
				bestFeatureId = featureId;
				bestInfoGain = information_gain;
			}
			}
		}
			
		
		
		//int bestFeatureId = DecisionTreeCommon.CalculateBestFeature(usedFeatures, root.evaluatedMovies/*, unknownMovie*/);
 		if(bestFeatureId!=-1){
			root.noBranch = new Node();
			root.yesBranch = new Node();
			root.featureId = bestFeatureId;	
			usedFeatures.add(root.featureId);
			
			root.noBranch.parent = root;
			root.yesBranch.parent = root;
			//root.noBranch.featureId = bestFeatureId;
		//	root.yesBranch.featureId = bestFeatureId;
			root.noBranch.evaluatedMovies = getDividedMovies(root.evaluatedMovies, root.featureId, false);
			root.noBranch.evaluations=getEvaluationsForMovies(root.noBranch.evaluatedMovies, root.evaluations);
			root.yesBranch.evaluatedMovies = getDividedMovies(root.evaluatedMovies, root.featureId, true);
			root.yesBranch.evaluations=getEvaluationsForMovies(root.yesBranch.evaluatedMovies, root.evaluations);
			buildTree(root.noBranch);
			buildTree(root.yesBranch);	
			//root.evaluatedMovies=null;
			//root.evaluations=null; 				//??????????
			
		}
		else {
			return root;
		}
		
		return root;
	}
	
	
	
	public static boolean equalFeatures(int featureId, Movie unknown_movie){
		
		if(featureId==0){
			if( Integer.parseInt(unknown_movie.features.get(featureId).value) >=100)
				return true;				
			else
				return false;			
		}
		else if(featureId==19){
			if(Double.parseDouble(unknown_movie.features.get(featureId).value) >=3.0)
				return true;					
			else
				return false;	
		}
		else if(featureId==20){
			if(Integer.parseInt(unknown_movie.features.get(featureId).value) >=2000000)
				return true;	
			else
				return false;	
		}
		else if(featureId==21){
			if(Integer.parseInt(unknown_movie.features.get(featureId).value) >=2000)
				return true;	
			else
				return false;	
		}
		else{
			if(unknown_movie.features.get(featureId).value.equals("1"))
				return true;	
			else
				return false;	
		}
		
	}

	
	public Node traverse(Node root, Movie unknown_movie){
		if(root.yesBranch==null && root.noBranch==null){
			finalMovies = root.evaluatedMovies;
			finalEvals=root.evaluations;
	//		System.out.println("LEFT:"+root.evaluatedMovies.size());
		//	System.out.println(root.evaluations.get(0).evaluation);
			return root;
		}
		
		boolean val=equalFeatures(root.featureId, unknown_movie);
		if(val==true) traverse(root.yesBranch,unknown_movie);
		else traverse(root.noBranch,unknown_movie);
		
		//System.out.println("gdfg  "+root.evaluatedMovies.size());
		
		return root;
	}
	
	
	
	
	private static ArrayList<Evaluation> getEvaluationsForMovies(ArrayList<Movie> evaluatedMovies, ArrayList<Evaluation> allEvals){
		ArrayList<Evaluation> newEvals=new ArrayList<>();
		for(Movie m : evaluatedMovies ){
			for(Evaluation e : allEvals){
				if(e.movieId==m.movieId){
					newEvals.add(new Evaluation(e.movieId, e.evaluation));
				}
			}
		}
		return newEvals;
	}
	
	
	//(t/f or range)
	/**
	 * 
	 * @param evaluatedMovies
	 * @param featureId
	 * @param yesBranch - if we return movies for yes branch
	 * @return
	 */
	private static ArrayList<Movie> getDividedMovies(ArrayList<Movie> evaluatedMovies, Integer featureId,/* Movie unknownMovie,*/ boolean yesBranch){
	
		ArrayList<Movie> returnedMovies = new ArrayList<>();
		//1 - length
		//20 - avg. vote
		//21 - budget
		//22 - year the movie was released
		if(yesBranch){
			for(int i =0; i < evaluatedMovies.size();i++){
				if(featureId==0 && Integer.parseInt(evaluatedMovies.get(i).features.get(featureId).value) >=100){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else if(featureId==19 && Double.parseDouble(evaluatedMovies.get(i).features.get(featureId).value) >=3.0){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else if(featureId==20 && Integer.parseInt(evaluatedMovies.get(i).features.get(featureId).value) >=2000000){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else if(featureId==21 && Integer.parseInt(evaluatedMovies.get(i).features.get(featureId).value) >=2000){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else{
					if(evaluatedMovies.get(i).features.get(featureId).value.equals("1")){
						returnedMovies.add(evaluatedMovies.get(i));
					}
				}
			}
		}
		else{
			for(int i =0; i < evaluatedMovies.size();i++){
				if(featureId==0 && Integer.parseInt(evaluatedMovies.get(i).features.get(featureId).value) <100){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else if(featureId==19 && Double.parseDouble(evaluatedMovies.get(i).features.get(featureId).value) <3.0){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else if(featureId==20 && Integer.parseInt(evaluatedMovies.get(i).features.get(featureId).value) <2000000){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else if(featureId==21 && Integer.parseInt(evaluatedMovies.get(i).features.get(featureId).value) <2000){
					returnedMovies.add(evaluatedMovies.get(i));
				}
				else{
					if(evaluatedMovies.get(i).features.get(featureId).value.equals("0")){
						returnedMovies.add(evaluatedMovies.get(i));
					}
				}
			}
		}
		return returnedMovies;
		
	}
	
	
}
